#ifndef SSL_H
#define SSL_H

class SSLContext;

class SSL
{
	public:
		SSL(const String&);
		~SSL();

		// setup() and teardown() are application global...only call them
		// once apiece for the entire application
		//
		static bool8 setup();		// before creating any SSL objects
		static void teardown();		// after deleting all SSL objects

		void setRecvTimeout(int32 seconds);		// defaults to 120 (2 minutes)

		bool8 connect(uint32 ipaddr, int32 port = 443);
		bool8 connect(char* hostname, int32 port = 443);

		bool8 send(uint8* iBuf, uint32 iAmt);
		bool8 recv(uint8* oBuf, uint32* oAmt);

		void close();

		enum Result
		{
			Success			= 0,

			E_Timeout		= -1,
			E_ConnClosed	= -2,
			E_InternalError	= -3,
			E_ConnFailed	= -4,
			E_ConnAlready	= -5,
			E_NotAuthorized = -6
		};

		Result getLastResult();

	public:
		bool8 sendBytes(uint8*, uint32);
		bool8 recvBytes(uint8*, uint32, uint32*);

	protected:
		bool8 open(uint32, int32);

		bool8 negotiateContext();

		bool8 getEmptyClientCredentials();
		void getNewClientCredentials();
		bool8 getClientContext(uint8*,uint32*, uint8*,uint32*, bool8*, bool8*);

#ifdef DEBUG
		void showContext();
		void showContextCaps(uint32);
		void showCertificate(void*);
		void showRemoteCertificate();
		void DumpHex(uint8*, uint32);
#endif

	protected:
		static HINSTANCE			shSSL;
		static int32				sMaxTokenSize;
		
	protected:
		SOCKET		sock;
		SSLContext*	context;
		int32		recvTimeout;
		Result		lastResult;

	private:
		String		certSubjectStr;
};

inline void
SSL::setRecvTimeout(int32 seconds)
{
	if (seconds >= 0)
		recvTimeout = seconds;
}

inline SSL::Result
SSL::getLastResult()
{
	return lastResult;
}

#endif
